/* 
 * File:   MROperator.cpp
 * Author: marcio
 * 
 * Created on 30 de Agosto de 2013, 15:37
 */

#include "MROperator.h"
#include "Problem.h"
#include "MRCodification.h"
#include "oCrossover.h"
#include "oMutation.h"
#include "oInitializer.h"

#include <cstdlib>

#define LI                -10.0
#define LS                 10.0
#define GENES                3
#define SIGMA             1.0
#define PROBMUTA     0.25
#define ALPHA            0.25

const MROperator MROperator::obj;

MROperator::MROperator() {
}

MROperator::~MROperator() {
}

const char* MROperator::name()const {
    return "MR-Operator";
}

/* inicializa 1 cromossomo com 3 genes, com valores double entre -10 e +10 */
class MROperator::INIT : public oInitializer {

    const char* name()const {
        return "MR-init";
    }

    void initialize(Problem* prob, Codification* ind) throw (exception) {
        MRCodification* codif = dynamic_cast<MRCodification*> (ind);
        for (int i = 0; i < GENES; i++)
            codif->cromo[i] = UniformRealDistribution::rand(LI, LS);
    };
};

class MROperator::CROSS : public oCrossover {

    const char* name()const {
        return "MR-cross-Heurística";
    }

    /**
     * Crossover heurístico: c = p1 + r(p1-p2), onde p1 é melhor que p2, r ~ U(0,1).
     * @param prob
     * @param ind1 é a codificação do pai1. Obrigatoriamente ind1 deve ser melhor que ind2
     * @param ind2 é a codificação do pai2
     * @return 
     */
    Codification* crossover(Problem* prob, Codification* ind1, Codification* ind2) throw (exception) {
        MRCodification* codif1 = dynamic_cast<MRCodification*> (ind1);
        MRCodification* codif2 = dynamic_cast<MRCodification*> (ind2);
        MRCodification* child = dynamic_cast<MRCodification*> (codif1->New(prob));
        double r = UniformRealDistribution::rand(0, 1);
        for (int i = 0; i < GENES; i++) {
            child->cromo[i] = codif1->cromo[i] + r * (codif1->cromo[i] - codif2->cromo[i]);
            if (child->cromo[i] > LS)
                child->cromo[i] = LS;
            if (child->cromo[i] < LI)
                child->cromo[i] = LI;
        }
        return child;
    };
};

class MROperator::CROSS2 : public oCrossover {

    const char* name() const {
        return "MR-cross-BLXalpha";
    }

    /**
     * Crossover BLXalpha com Beta diferente para cada gene
     * @param prob
     * @param ind1 codificação do pai1
     * @param ind2 codificaçao do pai2
     * @return 
     */
    Codification* crossover(Problem* prob, Codification* ind1, Codification* ind2) throw (exception) {
        MRCodification* codif1 = dynamic_cast<MRCodification*> (ind1);
        MRCodification* codif2 = dynamic_cast<MRCodification*> (ind2);
        MRCodification* child = dynamic_cast<MRCodification*> (codif1->New(prob));
        for (int i = 0; i < GENES; i++) {
            child->cromo[i] = codif1->cromo[i] + UniformRealDistribution::rand(-ALPHA, 1 + ALPHA)*(codif2->cromo[i] - codif1->cromo[i]);
            if (child->cromo[i] > LS)
                child->cromo[i] = LS;
            if (child->cromo[i] < LI)
                child->cromo[i] = LI;
        }
        return child;
    };

};

class MROperator::MUT : public oMutation {

    const char* name()const {
        return "MR-mut-gaussiana";
    }

    void mutation(Problem* prob, Codification* ind) throw (exception) {
        MRCodification* codif = dynamic_cast<MRCodification*> (ind);

        if (UniformRealDistribution::rand(0, 1) < PROBMUTA) {
            int gene = UniformIntDistribution::rand(0, GENES - 1);
            codif->cromo[gene] = GaussianDistribution::rand(codif->cromo[gene], SIGMA);
            if (codif->cromo[gene] > LS)
                codif->cromo[gene] = LS;
            if (codif->cromo[gene] < LI)
                codif->cromo[gene] = LI;
        }
    };
};

Node* MROperator::NewService(int index)const {
    switch (index) {
        case 0: return new INIT();
        case 1: return new CROSS2();
        case 2: return new MUT();
        case 3: return new CROSS();
    }
    return NULL;
}
